<template>
  <Form
    v-bind="getBindValue"
    :class="getFormClass"
    :form="formElRef"
    :model="formModel"
    @keypress.enter="handleEnterPress"
  >
    <Row v-bind="getRow">
      <slot name="formHeader"></slot>
      <template v-for="(schema, index) in getSchema">
        <FormItem
          :key="schema.field + index"
          :isAdvanced="fieldsIsAdvancedMap[schema.field]"
          :tableAction="tableAction"
          :formActionType="formActionType"
          :schema="schema"
          :formProps="getProps"
          :allDefaultValues="defaultValueRef"
          :formModel="formModel"
          :setFormModel="setFormModel"
        >
          <template
            v-slot:[item]="data"
            v-for="item in Object.keys($scopedSlots)"
          >
            <slot :name="item" v-bind="data || {}"></slot>
          </template>
        </FormItem>
      </template>
      <slot name="action">
        <FormAction
          v-bind="getFormActionBindProps"
          @toggle-advanced="handleToggleAdvanced"
        >
          <template
            #[item]="data"
            v-for="item in [
              'resetBefore',
              'submitBefore',
              'advanceBefore',
              'advanceAfter',
            ]"
          >
            <slot :name="item" v-bind="data || {}"></slot>
          </template>
        </FormAction>
      </slot>
      <div class="ant-col ant-col-24">
        <slot name="formFooter"></slot>
      </div>
    </Row>
  </Form>
</template>
<script>
import {
  defineComponent,
  reactive,
  ref,
  computed,
  unref,
  onMounted,
  watch,
  nextTick,
  getCurrentInstance,
} from "vue";
import { Form, Row } from "ant-design-vue";
import FormItem from "./components/FormItem.vue";
import FormAction from "./components/FormAction.vue";
import { dateItemType } from "./helper";
import { dateUtil } from "@/utils/dateUtil";
// import { cloneDeep } from 'lodash-es';
import { deepMerge } from "@/utils";
import { useFormValues } from "./hooks/useFormValues";
import useAdvanced from "./hooks/useAdvanced";
import { useFormEvents } from "./hooks/useFormEvents";
import { createFormContext } from "./hooks/useFormContext";
import { useAutoFocus } from "./hooks/useAutoFocus";
// import { useModalContext } from '@/components/Modal';
import { useDebounceFn } from "@vueuse/core";
import { basicProps } from "./props";
import { useDesign } from "@/hooks/web/useDesign";
import { cloneDeep } from "lodash-es";
export default defineComponent({
  name: "BasicForm",
  components: { FormItem, Form, Row, FormAction },
  props: basicProps,
  emits: [
    "advanced-change",
    "reset",
    "submit",
    "register",
    "field-value-change",
  ],
  setup(props, { emit, attrs, expose }) {
    const formModel = reactive({});
    // const modalFn = useModalContext();
    const advanceState = reactive({
      isAdvanced: true,
      hideAdvanceBtn: false,
      isLoad: false,
      actionSpan: 6,
    });
    const defaultValueRef = ref({});
    const isInitedDefaultRef = ref(false);
    const propsRef = ref({});
    const schemaRef = ref(null);

    const instance = getCurrentInstance();
    console.log(131, instance);
    const formElRef = Form.createForm(instance, { name: "advanced_search" });
    const { prefixCls } = useDesign("basic-form");
    // Get the basic configuration of the form
    const getProps = computed(() => {
      return Object.assign(Object.assign({}, props), unref(propsRef));
    });
    const getFormClass = computed(() => {
      return [
        prefixCls,
        {
          [`${prefixCls}--compact`]: unref(getProps).compact,
        },
      ];
    });
    // Get uniform row style and Row configuration for the entire form
    const getRow = computed(() => {
      const { baseRowStyle = {}, rowProps } = unref(getProps);
      return Object.assign({ style: baseRowStyle }, rowProps);
    });
    const getBindValue = computed(() =>
      Object.assign(
        Object.assign(Object.assign({}, attrs), props),
        unref(getProps)
      )
    );
    const getSchema = computed(() => {
      const schemas = unref(schemaRef) || unref(getProps).schemas;
      for (const schema of schemas) {
        const {
          defaultValue,
          component,
          isHandleDateDefaultValue = true,
        } = schema;
        // handle date type
        if (
          isHandleDateDefaultValue &&
          defaultValue &&
          dateItemType.includes(component)
        ) {
          if (!Array.isArray(defaultValue)) {
            schema.defaultValue = dateUtil(defaultValue);
          } else {
            const def = [];
            defaultValue.forEach((item) => {
              def.push(dateUtil(item));
            });
            schema.defaultValue = def;
          }
        }
      }
      if (unref(getProps).showAdvancedButton) {
        return cloneDeep(
          schemas.filter((schema) => schema.component !== "Divider")
        );
      } else {
        return cloneDeep(schemas);
      }
    });
    const { handleToggleAdvanced, fieldsIsAdvancedMap } = useAdvanced({
      advanceState,
      emit,
      getProps,
      getSchema,
      formModel,
      defaultValueRef,
    });
    const { handleFormValues, initDefault } = useFormValues({
      getProps,
      defaultValueRef,
      getSchema,
      formModel,
    });
    useAutoFocus({
      getSchema,
      getProps,
      isInitedDefault: isInitedDefaultRef,
      formElRef: formElRef,
    });
    const {
      handleSubmit,
      setFieldsValue,
      clearValidate,
      validate,
      validateFields,
      getFieldsValue,
      updateSchema,
      resetSchema,
      appendSchemaByField,
      removeSchemaByField,
      resetFields,
      scrollToField,
    } = useFormEvents({
      emit,
      getProps,
      formModel,
      getSchema,
      defaultValueRef,
      formElRef: formElRef,
      schemaRef: schemaRef,
      handleFormValues,
    });
    createFormContext({
      resetAction: resetFields,
      submitAction: handleSubmit,
    });
    watch(
      () => unref(getProps).model,
      () => {
        const { model } = unref(getProps);
        if (!model) return;
        setFieldsValue(model);
      },
      {
        immediate: true,
      }
    );
    watch(
      () => unref(getProps).schemas,
      (schemas) => {
        resetSchema(schemas !== null && schemas !== void 0 ? schemas : []);
      }
    );
    watch(
      () => getSchema.value,
      (schema) => {
        // nextTick(() => {
        //   var _a;
        //   //  Solve the problem of modal adaptive height calculation when the form is placed in the modal
        //   (_a = modalFn === null || modalFn === void 0 ? void 0 : modalFn.redoModalHeight) === null || _a === void 0 ? void 0 : _a.call(modalFn);
        // });
        if (unref(isInitedDefaultRef)) {
          return;
        }
        if (schema === null || schema === void 0 ? void 0 : schema.length) {
          initDefault();
          isInitedDefaultRef.value = true;
        }
      }
    );
    watch(
      () => formModel,
      useDebounceFn(() => {
        unref(getProps).submitOnChange && handleSubmit();
      }, 300),
      { deep: true }
    );
    async function setProps(formProps) {
      propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
    }
    function setFormModel(key, value) {
      formModel[key] = value;
      const { validateTrigger } = unref(getBindValue);
      if (!validateTrigger || validateTrigger === "change") {
        validateFields([key]).catch((_) => {});
      }
      emit("field-value-change", key, value);
    }
    function handleEnterPress(e) {
      const { autoSubmitOnEnter } = unref(getProps);
      if (!autoSubmitOnEnter) return;
      if (e.key === "Enter" && e.target && e.target instanceof HTMLElement) {
        const target = e.target;
        if (
          target &&
          target.tagName &&
          target.tagName.toUpperCase() == "INPUT"
        ) {
          handleSubmit();
        }
      }
    }
    const formActionType = {
      getFieldsValue,
      setFieldsValue,
      resetFields,
      updateSchema,
      resetSchema,
      setProps,
      removeSchemaByField,
      appendSchemaByField,
      clearValidate,
      validateFields,
      validate,
      submit: handleSubmit,
      scrollToField: scrollToField,
    };
    expose({ validate });
    onMounted(() => {
      initDefault();
      emit("register", formActionType);
    });

    return Object.assign(
      {
        getBindValue,
        validate,
        handleToggleAdvanced,
        handleEnterPress,
        formModel,
        defaultValueRef,
        advanceState,
        getRow,
        getProps,
        formElRef,
        getSchema,
        formActionType: formActionType,
        setFormModel,
        getFormClass,
        getFormActionBindProps: computed(() =>
          Object.assign(Object.assign({}, getProps.value), advanceState)
        ),
        fieldsIsAdvancedMap,
      },
      formActionType
    );
  },
});
</script>
<style lang="less">
@prefix-cls: ant-basic-form;

.@{prefix-cls} {
  .ant-form-item {
    display: flex;
    &-label label::after {
      margin: 0 6px 0 2px;
    }

    &-with-help {
      margin-bottom: 0;
    }

    &:not(.ant-form-item-with-help) {
      margin-bottom: 20px;
    }

    &.suffix-item {
      .ant-form-item-children {
        display: flex;
      }

      .ant-form-item-control {
        margin-top: 4px;
      }

      .suffix {
        display: inline-flex;
        padding-left: 6px;
        margin-top: 1px;
        line-height: 1;
        align-items: center;
      }
    }
  }

  .ant-form-explain {
    font-size: 14px;
  }

  &--compact {
    .ant-form-item {
      margin-bottom: 8px !important;
    }
  }
}
</style>
